tree grammar BPSLWalker;

options{
	tokenVocab=BPSL;
	ASTLabelType=CommonTree;
}

@header{
	package modelbuilding.analysis.bpsl;
	
	import java.util.Map;
	import java.util.HashMap;
	import java.util.List;
	import java.util.LinkedList;

}

@members{
	// declare and instantiate the symbol table used to track defined variables as a class atribute of the generated tree walker
	// symbol( x , y ) with x = variablename; y = type of the variable ( one of class, typed variable or method )
	// BPSLVarType is the Java enum capturing these 3 possibilities
	private Map<String, BPSLTermType> symbols = new HashMap<String, BPSLTermType>();
	private List<Atom> atoms = new LinkedList<Atom>(); 
	private BPSLPredicateSpace predicates = BPSLPredicateSpace.getInstance();
	  
}

/*The AST has the form of a flat tree (list) whos elements are trees with height 1

List -> ( CLASSDEF-Tree | TYPEDVARDEF-Tree | METHODDEF-Tree | )+, PREDICATE1, PREDICATE2, PREDICATE3,..
with	:	
CLASSDEF-Tree : root "CLASSDEF" - children ID1, ID2, ID3,...
...
PREDICATE-Tree : root "PREDICATE" - children ID1, ID2 ( exactly 2 children )

The generated treewalker needs as input a tree of the described structure. The AST generated by the associated
parser grammar produces such a tree from the input design pattern specification file
*/


/*simple production rule			
specification	:	(  ^(CLASSDEF ID+ ) |  ^(TYPEDVARDEF ID+ ) | ( ^(METHODDEF ID+ ) )+ ( ^(PREDICATE ID ID) )*
			;
			
corresponeds to			Variable definitios - VarDef Block					|	Formula - Predicate Block
*/

/*Production rule extended with actions to verify some rules for a valid SBPSL especification
--> A variable can be declared only once.
--> A variable used in the formula has to be declared.
--> A predicate has to be defined for the domain of its arguments		
*/
specification	returns [BPSLFormula formula]
			@after { formula = new BPSLFormula(symbols, atoms); }
			:	(
				^(CLASSDEF (a=ID
				{	
					if ( ! symbols.containsKey($a.text) ) {
						//add variable to the symbol table
						symbols.put($a.text, BPSLTermType.CLASS);
					}
					else {
						// variable already used. treat errror
					}
				})+
				)
			|	

				^(TYPEDVARDEF (a=ID
				{
					if ( ! symbols.containsKey($a.text) ) {
						//add variable to the symbol table
						symbols.put($a.text, BPSLTermType.TYPEDVARIABLE);
					}
					else {
						// variable allready used. treat errror
					}	
				})+
				)
				
			|
	
				^(METHODDEF (a=ID
				{
					if ( ! symbols.containsKey($a.text) ) {
						//add variable to the symbol table
						symbols.put($a.text, BPSLTermType.METHOD);
					}
					else {
						// variable allready used. treat errror
					}	
				})+
				)
			)+
				
				( ^(c=PREDICATE a=ID b=ID)
				{ 
					BPSLTermType aType, bType;
					//verify if ID a has been declared and get his type
					aType = symbols.get($a.text);
					//verify if ID b has been declard and get his type
					bType = symbols.get($b.text);
					//if both have been declared verify if predicate is defined for this domain
					if (aType != null && bType != null) {
						//if predicate is defined add adge to graph
						if ( predicates.isDefinedOnDomain($c.text, symbols.get($a.text), symbols.get($b.text)) ){
							atoms.add( new Atom(BPSLPredicates.getEnum($c.text), $a.text, $b.text) );	
						}
						//else treat error
						else {
						} 
					
					}
					//else treat error
					else {
					}
						
				}
				)*
			;
